package vn.edu.fpt.xml.back.daos;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import vn.edu.fpt.xml.back.entities.JpaEntity;

import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.Transactional;
import java.lang.reflect.ParameterizedType;
import java.util.List;

/**
 * Created by hiephn on 2014/04/25.
 */
public abstract class GenericJpaDao<T extends JpaEntity> implements GenericDao<T> {

    private static final Logger LOGGER = LoggerFactory.getLogger(GenericJpaDao.class);
    protected Class<T> entityClass;
    protected EntityManager entityManager;

    @PersistenceContext(unitName = "xmlNewsCloudBackendPersistenceUnit")
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
        this.entityManager.setFlushMode(FlushModeType.COMMIT);
    }

    public GenericJpaDao() {
        ParameterizedType genericSupperClass = (ParameterizedType) this.getClass().getGenericSuperclass();
        this.entityClass = (Class<T>) genericSupperClass.getActualTypeArguments()[0];
    }


    public void flush()  {
        entityManager.flush();
    }

    public void refresh(T entity)  {
        entityManager.refresh(entity);
    }

    @Override
    public T save(T entity) {
        if (StringUtils.isEmpty(entity.getId())) {

            // new entity creation, set id and persist
            entityManager.persist(entity);
        } else {

            // created entity, just merge
            entityManager.merge(entity);
        }
        return entity;
    }

    @Override
    public void remove(final T entity) {
        if (entity != null) {
            entityManager.remove(entity);
        }
    }

    @Override
    public T findById(final String id) {
        return entityManager.find(entityClass, id);
    }

    /**
     * Execute the query and return the query results as a List in transaction.
     * @param query query
     * @return a list of the results
     */
    @SuppressWarnings("unchecked")
    protected List<T> executeList(Query query) {
        return query.getResultList();
    }

    /**
     * Execute a SELECT query that returns a single result in transaction.
     * @param query query
     * @return the result or null if not found
     */
    protected T executeSingle(Query query) {
        List<T> resultList = executeList(query);
        if (!resultList.isEmpty()) {
            return resultList.get(0);
        } else {
            return null;
        }
    }

    public void clear() {
        entityManager.clear();
    }

    public void detach(T entity) {
        entityManager.detach(entity);
    }
}
